package org.go.scheduler.rmi;

import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.util.concurrent.ConcurrentHashMap;

import org.go.domain.GoDomain;
import org.go.expcetion.GoException;
import org.go.expcetion.JobPersistenceException;
import org.go.expcetion.SchedulerException;
import org.go.log.Log;
import org.go.log.LoggerFactory;
import org.go.scheduler.Scheduler;
import org.go.scheduler.SchedulerResources;
import org.go.threadpool.GoThreadPool;
import org.go.threadpool.GoThreadPoolRepository;
import org.go.trigger.Calendar;
import org.go.trigger.Trigger;
import org.go.trigger.TriggerKey;
import org.go.work.Work;
import org.go.work.WorkKey;

/**
 * <p>
 * An implementation of the <code>Scheduler</code> interface that remotely
 * proxies all method calls to the equivalent call on a given <code>QuartzScheduler</code>
 * instance, via RMI.
 * </p>
 * 
 * @see org.go.core.Scheduler
 * 
 * @author hejie
 */
public class RemoteScheduler implements Scheduler {
	private static final Log log = LoggerFactory.getLog(RemoteScheduler.class);
	private SchedulerResources resources;
	private IRmiScheduler rmiScheduler = null;

	public RemoteScheduler(SchedulerResources schedId) throws GoException {
		this.resources = schedId;
		bind();
	}

	/**
	 * <p>
	 * Bind the scheduler to an RMI registry.
	 * </p>
	 */
	private void bind() throws GoException {
		try {
			rmiScheduler = new RMIServerScheduler(resources);
			String host = resources.getRMIRegistryHost();
			// don't export if we're not configured to do so...
			if (host == null || host.length() == 0) {
				return;
			}
			int port = resources.getRMIServerPort();

			//			if (port > 0) {
			//				rmiScheduler = (IRmiScheduler) UnicastRemoteObject.exportObject(rmiScheduler, resources.getRMIServerPort());
			//			} else {
			//				rmiScheduler = (IRmiScheduler) UnicastRemoteObject.exportObject(rmiScheduler);
			//			}

			Registry registry = null;
			if (resources.getRMICreateRegistryStrategy().equals(GoDomain.CREATE_REGISTRY_AS_NEEDED)) {
				try {
					// First try to get an existing one, instead of creating it,
					// since if
					// we're in a web-app being 'hot' re-depoloyed, then the JVM
					// still
					// has the registry that we created above the first time...
					registry = LocateRegistry.getRegistry(resources.getRMIRegistryPort());
					registry.list();
				} catch (Exception e) {
					registry = LocateRegistry.createRegistry(resources.getRMIRegistryPort());
				}
			} else if (resources.getRMICreateRegistryStrategy().equals(GoDomain.CREATE_REGISTRY_ALWAYS)) {
				try {
					registry = LocateRegistry.createRegistry(resources.getRMIRegistryPort());
				} catch (Exception e) {
					// Fall back to an existing one, instead of creating it, since
					// if
					// we're in a web-app being 'hot' re-depoloyed, then the JVM
					// still
					// has the registry that we created above the first time...
					registry = LocateRegistry.getRegistry(resources.getRMIRegistryPort());
				}
			} else {
				registry = LocateRegistry.createRegistry(port);
				//registry = LocateRegistry.getRegistry(host, port);
			}
			String bindName = resources.getRMIBindName();
			//registry.bind(bindName, rmiScheduler);
			registry.rebind(bindName, rmiScheduler);
			//boolean boundRemotely = true;
			//			if (resources.getRMIServerPort() > 0) {
			//				rmiScheduler = (IRmiScheduler) UnicastRemoteObject.exportObject(rmiScheduler, port);
			//			} else {
			//				rmiScheduler = (IRmiScheduler) UnicastRemoteObject.exportObject(rmiScheduler);
			//			}
			log.debug("Scheduler bound to RMI registry under name '" + bindName + "'");
		} catch (RemoteException e1) {
			log.error("Scheduler bound to RMI registry Error {}", e1.getMessage());
		} catch (SchedulerException e) {
			log.error("Scheduler bound to RMI registry Error {}", e.getMessage());
		} catch (Exception e) {
			log.error("Scheduler bound to RMI registry Error {}", e.getMessage());
			throw new GoException(e);
		}
		/*
		 * catch (AlreadyBoundException e) {
			log.error("Scheduler bound to RMI registry Error {}", e.getMessage());
		} */
	}

	@Override
	public ConcurrentHashMap<String, Object> getContext() {
		return null;
	}

	@Override
	public String getJobGroupNames() {
		return null;
	}

	@Override
	public SchedulerResources getResource() {
		return resources;
	}

	@Override
	public String getSchedulerName() throws SchedulerException {
		return resources.getName();
	}

	@Override
	public Trigger getTrigger(TriggerKey tKey) {
		return null;
	}

	@Override
	public boolean isShutdown() throws SchedulerException {
		return false;
	}

	@Override
	public void notifySchedulerListenersError(String string, GoException se) {

	}

	@Override
	public void notifySchedulerListenersError(String string, JobPersistenceException se) {

	}

	@Override
	public void scheduler(Work work, Trigger trigger) throws SchedulerException {
		try {
			rmiScheduler.scheduler(work, trigger);
		} catch (RemoteException e) {
			log.error("{}", e);
		}
	}

	//	@Override
	//	public void startDelayed(int seconds) throws SchedulerException {
	//
	//	}

	@Override
	public void shutdown(boolean cleanShutdown) throws SchedulerException {

	}

	@Override
	public void shutdownNow() throws SchedulerException {
		GoThreadPool poolWrapper = GoThreadPoolRepository.getInstance().lookup();
		poolWrapper.shutdownNow();
	}

	//@Override
	//	public void startAll() throws GoException {
	//		try {
	//			//rmiScheduler.startAll();
	//		} catch (RemoteException e) {
	//			e.printStackTrace();
	//		} catch (SchedulerException e) {
	//			e.printStackTrace();
	//		}
	//	}

	@Override
	public void unscheduleWork(TriggerKey tKey) {

	}

	@Override
	public void addCalendar(String calName, Calendar calendar, boolean replace, boolean updateTriggers) throws SchedulerException {

	}

	@Override
	public void pauseWork(WorkKey workKey) throws SchedulerException {

	}

	@Override
	public void pauseAllWorks() throws SchedulerException {

	}

	@Override
	public String getVersion() {
		// TODO Auto-generated method stub
		return null;
	}
}
